﻿using System;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
using Gem;
using GemGui.Annotations;

namespace GemGui.ViewModel
{
    /// <summary>
    /// A view model for a <see cref="EnvironmentDefinition"/> object.
    /// </summary>
    public class EnvironmentViewModel : INotifyPropertyChanged
    {
        private readonly EnvironmentDefinition m_modelDefinition;

        private bool m_showInfo;
        private string m_lastCustomInformation;

        public EnvironmentViewModel(EnvironmentDefinition modelDefinition, SccEnvironmentsViewModel container, int index)
        {
            Utils.GuardNotNull(modelDefinition, "relatedDefinition");

            m_modelDefinition = modelDefinition;
            Container = container;
            ShowInfo = true;

            NonHoverColor = index % 2 == 0
                ? new SolidColorBrush(Colors.White)
                : new SolidColorBrush(Colors.PapayaWhip);
        }

        #region Visual properties

        /// <summary>
        /// Gets the parent container to this environment view model.
        /// </summary>
        public SccEnvironmentsViewModel Container { get; private set; }

        /// <summary>
        /// Gets the folder name.
        /// </summary>
        public string FolderName
        {
            get
            {
                return m_modelDefinition.FolderName;
            }
        }

        /// <summary>
        /// Gets the SCC related information for the environment's folder.
        /// </summary>
        public string FolderSccInformation
        {
            get
            {
                return m_modelDefinition.FolderSccInformation;
            }
        }

        /// <summary>
        /// Gets or sets user custom information used to describe the SCC-related folder.
        /// </summary>
        public string FolderCustomInformation
        {
            get
            {
                return m_modelDefinition.FolderCustomInformation;
            }

            set
            {
                m_modelDefinition.FolderCustomInformation = value;
            }
        }

        /// <summary>
        /// Gets or sets whether this environment can be viewed on the quick-view.
        /// </summary>
        public bool IsOnQuickView
        {
            get
            {
                return m_modelDefinition.IsViewable;
            }

            set
            {
                m_modelDefinition.IsViewable = value;

                Container.OnPropertyChanged("EnvironmentsStatus");
                CommitEnvironmentInformationTransaction();
            }
        }

        /// <summary>
        /// Gets the information to present for an SCC environment.
        /// </summary>
        public string Info
        {
            get
            {
                string customInfo = string.Empty;

                if (!string.IsNullOrEmpty(FolderCustomInformation))
                {
                    customInfo = string.Format(CultureInfo.InvariantCulture, @"{0}{1}", Environment.NewLine, FolderCustomInformation);
                }

                return string.Format(CultureInfo.InvariantCulture, "{0} | {1}{2}", m_modelDefinition.FolderName, m_modelDefinition.FolderSccInformation, customInfo);
            }
        }

        /// <summary>
        /// Gets whether to show the environment's info.
        /// </summary>
        public bool ShowInfo
        {
            get
            {
                return m_showInfo;
            }

            set
            {
                m_showInfo = value;

                OnPropertyChanged("IsInfoVisible");
                OnPropertyChanged("IsCustomInfoVisible");
            }
        }

        /// <summary>
        /// Gets whether to show the label of the <see cref="Info"/> property.
        /// Is the opposite of <see cref="IsCustomInfoVisible"/>.
        /// </summary>
        public Visibility IsInfoVisible
        {
            get
            {
                return ShowInfo ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        /// <summary>
        /// Gets whether to show the custom information text-box (for property <see cref="FolderCustomInformation"/>.
        /// Is the opposite of <see cref="IsInfoVisible"/>.
        /// </summary>
        public Visibility IsCustomInfoVisible
        {
            get
            {
                return ShowInfo ? Visibility.Collapsed : Visibility.Visible;
            }
        }

        /// <summary>
        /// The brush defining the visible background of the environment view when not hovering over with the mouse.
        /// </summary>
        public Brush NonHoverColor { get; private set; }

        #endregion

        #region Actions

        /// <summary>
        /// Set/reset the control edit mode.
        /// </summary>
        /// <param name="canEdit">Whether the control allows editing.</param>
        public void SetEditable(bool canEdit)
        {
            ShowInfo = !canEdit;

            Container.EnableRefreshEnvironment = !canEdit; // Stop refreshing for the editing while
        }

        public void StartCustomInformationTransaction()
        {
            m_lastCustomInformation = FolderCustomInformation;
        }

        public void RollbackCustomInformationTransaction()
        {
            FolderCustomInformation = m_lastCustomInformation;

            OnPropertyChanged("FolderCustomInformation");
        }

        public void CommitEnvironmentInformationTransaction()
        {
            Container.SaveConfiguration();
        }

        #endregion

        #region INotifyProperyChanged implementation

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
}
